package encrypt

import (
	"bytes"
	"crypto/cipher"
	"crypto/des"
	"encoding/base64"
	"fmt"
	"math/rand"
	"time"
)

//
//func main() {
//
//	word := flag.String("w", "", "加密串")
//	flag.Parse()
//
//	key := os.Getenv("MISSINGC")
//	if len(key ) == 0{
//		fmt.Println("can not found key in os")
//		return
//	}
//
//	fmt.Println(key)
//
//	if len(*word) == 0 {
//		fmt.Println("the word is empty")
//		return
//	}
//	fmt.Println(*word)
//
//	bs , _ := EnCrypt([]byte(*word), []byte(key))
//
//	fmt.Println(string(bs))
//
//	dds := Decrypt(bs, []byte(key))
//
//
//	fmt.Println(string(dds))
//}

// 加密方法
// 1、在加密字符串上的第3，5，6位增加随机字符做扰乱项
// 2、使用base64对待加密的字符串进行编码
// 3、使用DES对称加密方式进行加密，加密key写在系统的env参数中
// 4、系统中env参数取名与key，和加密等名称无关，尽量做到混淆
// 5、提供加密工具

func EnCrypt(word []byte, key []byte) ([]byte, error) {
	word = parseWord(word, 8)
	word = parseWord(word, 10)
	word = parseWord(word, 15)
	//fmt.Println(string(word))
	cipherText, err := AesEncrypt(word, key)
	if err != nil {
		fmt.Println(err.Error())
	}
	bs := base64.RawStdEncoding.EncodeToString(cipherText)
	//fmt.Println(bs)
	return []byte(bs), nil
}

func Decrypt(word []byte, key []byte) []byte {
	ds, _ := base64.RawStdEncoding.DecodeString(string(word))

	plainText, _ := AesDecrypt(ds, key)
	plainText = deParseWord(plainText, 15)
	plainText = deParseWord(plainText, 10)
	plainText = deParseWord(plainText, 8)
	//fmt.Println(string(plainText))
	return plainText
}

var letterRunes = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func RandLetter() byte {
	rand.Seed(time.Now().UnixNano())
	//b := make([]rune, 1)
	b := letterRunes[rand.Intn(len(letterRunes))]
	return b
}

// 整理字符串, 在字符串的3，5，7 位上增加随机字符
func parseWord(ds []byte, index int) []byte {
	ds = append(ds, 0)
	copy(ds[index:], ds[index-1:])
	ds[index] = RandLetter()
	return ds
}

func deParseWord(ds []byte, index int) []byte {
	ds = append(ds[:index], ds[index+1:]...)
	return ds
}

// des加密
func desEncrypt(plainText, key []byte) []byte {
	// 1. 建一个底层使用des的密码接口
	block, err := des.NewCipher(key)
	if err != nil {
		panic(err)
	}
	// 2. 明文填充
	newText := paddingLastGroup(plainText, block.BlockSize())
	// 3. 创建一个使用cbc分组接口
	iv := []byte("12345678")
	blockMode := cipher.NewCBCEncrypter(block, iv)
	// 4. 加密
	cipherText := make([]byte, len(newText))
	blockMode.CryptBlocks(cipherText, newText)
	// blockMode.CryptBlocks(newText, newText)
	return cipherText
}

// des解密
func desDecrypt(cipherText, key []byte) []byte {
	// 1. 建一个底层使用des的密码接口
	block, err := des.NewCipher(key)
	if err != nil {
		panic(err)
	}
	// 2. 创建一个使用cbc模式解密的接口
	iv := []byte("12345678")
	blockMode := cipher.NewCBCDecrypter(block, iv)
	// 3. 解密
	blockMode.CryptBlocks(cipherText, cipherText)
	// 4. cipherText现在存储的是明文, 需要删除加密时候填充的尾部数据
	plainText := unPaddingLastGroup(cipherText)
	return plainText
}

// des的CBC加密
// 编写填充函数, 如果最后一个分组字节数不够, 填充
// ......字节数刚好合适, 添加一个新的分组
// 填充个的字节的值 == 缺少的字节的数
func paddingLastGroup(plainText []byte, bloclSize int) []byte {
	// 1. 求出最后一个组中剩余的字节数 28 % 8 = 3...4  32 % 8 = 4 ...0
	padNum := bloclSize - len(plainText)%bloclSize
	// 2. 创建新的切片, 长度 == padNum, 每个字节值 byte(padNum)
	char := []byte{byte(padNum)} // 长度1,
	// 切片创建, 并初始化
	newPlain := bytes.Repeat(char, padNum)
	// 3. newPlain数组追加到原始明文的后边
	newText := append(plainText, newPlain...)
	return newText
}

// 去掉填充的数据
func unPaddingLastGroup(plainText []byte) []byte {
	// 1. 拿去切片中的最后一个字节
	length := len(plainText)
	lastChar := plainText[length-1] //
	number := int(lastChar)         // 尾部填充的字节个数
	return plainText[:length-number]
}

func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}

func PKCS7UnPadding(origData []byte) []byte {
	length := len(origData)
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}

//AES加密,CBC
/*func AesEncrypt(origData, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	blockSize := block.BlockSize()
	origData = PKCS7Padding(origData, blockSize)
	blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
	crypted := make([]byte, len(origData))
	blockMode.CryptBlocks(crypted, origData)
	return crypted, nil
}

//AES解密
func AesDecrypt(crypted, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	blockSize := block.BlockSize()
	blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
	origData := make([]byte, len(crypted))
	blockMode.CryptBlocks(origData, crypted)
	origData = PKCS7UnPadding(origData)
	return origData, nil
}*/
